//
//  MKUIEqualDivisionLayoutConstraint.m
//  MKUI
//
//  Created by 苏尚进 on 2025/7/10.
//  Copyright © 2025 moon. All rights reserved.
//

#import "MKUIEqualDivisionLayoutConstraint.h"
#import "MKUILayoutConstraintItemAttribute.h"

@implementation MKUIEqualDivisionLayoutConstraint
- (id)init{
    if(self=[super init]){
        self.itemFillCellBounds = YES;
    }
    return self;
}
- (id)copyWithZone:(NSZone *)zone{
    MKUIEqualDivisionLayoutConstraint *obj = [super copyWithZone:zone];
    obj.layoutDirection = self.layoutDirection;
    obj.layoutVerticalAlignment = self.layoutVerticalAlignment;
    obj.layoutHorizontalAlignment = self.layoutHorizontalAlignment;
    obj.contentInsets = self.contentInsets;
    obj.interitemSpacing = self.interitemSpacing;
    obj.itemFillCellBounds = self.itemFillCellBounds;
    obj.fixSizeToFitsBounds = self.fixSizeToFitsBounds;
    return obj;
}
- (MKCGAxis)layoutDirectionAxis{
    MKCGAxis X = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGAxisX:MKCGAxisY;
    return X;
}
- (CGSize)itemSizeForItem:(id<MKUILayoutConstraintItemProtocol>)item thatFits:(CGSize)size resizeItems:(BOOL)resizeItems{
    if(size.width<=0||size.height<=0){
        return CGSizeZero;
    }
    CGSize itemSize = CGSizeZero;
    CGSize limitSize = size;
    if(resizeItems){
        if([item respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
            itemSize = [item sizeThatFits:limitSize resizeItems:resizeItems];
        }else if([item respondsToSelector:@selector(sizeThatFits:)]){
            itemSize = [item sizeThatFits:limitSize];
        }else{
            itemSize = [item sizeOfLayout];
        }
    }else{
        itemSize = [item sizeOfLayout];
    }
    itemSize.width = MIN(itemSize.width,size.width);
    itemSize.height = MIN(itemSize.width,size.height);
    return itemSize;
}
- (nullable MKUILayoutConstraintItemAttributeSection *)itemAttributeSectionThatFits:(CGSize)size resizeItems:(BOOL)resizeItems{
    NSArray<id<MKUILayoutConstraintItemProtocol>> *layoutItems = self.layoutedItems;
    if(layoutItems.count==0) return nil;
    MKCGAxis X = [self layoutDirectionAxis];
    MKCGAxis Y = MKCGAxisReverse(X);
    
    UIEdgeInsets contentInsets = self.contentInsets;
    CGFloat spacing = self.interitemSpacing;
    
    CGSize originLimitSize = CGSizeMake(size.width-contentInsets.left-contentInsets.right, size.height-contentInsets.top-contentInsets.bottom);//限制在 size -contentInsets 矩形内
    CGFloat originLimitWidth = MKCGSizeGetLength(originLimitSize, X);
    CGFloat originLimitHeight = MKCGSizeGetLength(originLimitSize, Y);
    
    MKUILayoutConstraintItemAttributeSection *line = [[MKUILayoutConstraintItemAttributeSection alloc] init];
    CGRect f1 = CGRectZero;
    CGFloat count = layoutItems.count;
    CGFloat itemWidth = (MKCGSizeGetLength(originLimitSize, X)-MAX(0,count-1)*spacing)/count;
    MKCGRectSetLength(&f1, X, itemWidth);
    
    CGSize itemLimitSize = originLimitSize;
    MKCGSizeSetLength(&itemLimitSize, X, itemWidth);
    CGFloat maxItemHeight = 0;
    for(id<MKUILayoutConstraintItemProtocol> item in layoutItems){
        CGSize s = [self itemSizeForItem:item thatFits:itemLimitSize resizeItems:resizeItems];
        f1.size = s;
        maxItemHeight = MAX(maxItemHeight,MKCGSizeGetLength(s, Y));
        MKUILayoutConstraintItemAttribute *itemAttr = [[MKUILayoutConstraintItemAttribute alloc] initWithItem:item layoutFrame:f1];
        [line addItemAttribute:itemAttr];
    }
    if(self.fixSizeToFitsBounds){
        maxItemHeight = originLimitHeight;
    }
    maxItemHeight = MIN(maxItemHeight,originLimitHeight);
    CGFloat xPosition = 0;
    CGRect cellBounds = CGRectZero;
    MKCGSizeSetLength(&itemLimitSize, Y, maxItemHeight);
    for(MKUILayoutConstraintItemAttribute *itemAttr in line.itemAttributs){
        CGRect f1 = itemAttr.layoutFrame;
        if(self.itemFillCellBounds){
            f1.size = itemLimitSize;
        }
        MKCGRectSetMin(&f1, X, xPosition);
        xPosition += spacing+itemWidth;
        if(!self.itemFillCellBounds){
            cellBounds = f1;
            cellBounds.size = itemLimitSize;
            MKCGRectAlignToRect(&f1, X, MKCGRectAlignmentFromMKUILayoutConstraintHorizontalAlignment(self.layoutHorizontalAlignment), cellBounds);
            MKCGRectAlignToRect(&f1, Y, MKCGRectAlignmentFromMKUILayoutConstraintVerticalAlignment(self.layoutVerticalAlignment), cellBounds);
        }
        itemAttr.layoutFrame = f1;
    }
    CGRect lineFrame = CGRectZero;
    MKCGRectSetLength(&lineFrame, X, originLimitWidth);
    MKCGRectSetLength(&lineFrame, Y, maxItemHeight);
    line.layoutFrame = lineFrame;
    return line;
}
- (CGSize)sizeThatFits:(CGSize)size resizeItems:(BOOL)resizeItems{
    MKUILayoutConstraintItemAttributeSection *line = [self itemAttributeSectionThatFits:size resizeItems:resizeItems];
    if(!line) return CGSizeZero;
    
    UIEdgeInsets contentInsets = self.contentInsets;
    CGSize sizeFits = line.layoutFrame.size;
    if(sizeFits.width>0&&sizeFits.height>0){
        sizeFits.width += contentInsets.left+contentInsets.right;
        sizeFits.height += contentInsets.top+contentInsets.bottom;
    }
    return sizeFits;
}
- (void)layoutItemsWithResizeItems:(BOOL)resizeItems{
    CGSize size = self.bounds.size;
    MKUILayoutConstraintItemAttributeSection *line = [self itemAttributeSectionThatFits:size resizeItems:resizeItems];
    if(!line)return;
    UIEdgeInsets contentInsets = self.contentInsets;
    CGRect bounds = UIEdgeInsetsInsetRect(self.bounds, contentInsets);
    CGRect f1 = line.layoutFrame;
    MKCGAxis X = [self layoutDirectionAxis];
    MKCGAxis Y = MKCGAxisReverse(X);
    
    MKCGRectAlignment alignX = self.layoutDirection==MKUILayoutConstraintDirectionVertical?MKCGRectAlignmentFromMKUILayoutConstraintVerticalAlignment(self.layoutVerticalAlignment):MKCGRectAlignmentFromMKUILayoutConstraintHorizontalAlignment(self.layoutHorizontalAlignment);
    MKCGRectAlignment alignY = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGRectAlignmentFromMKUILayoutConstraintVerticalAlignment(self.layoutVerticalAlignment):MKCGRectAlignmentFromMKUILayoutConstraintHorizontalAlignment(self.layoutHorizontalAlignment);
    MKCGRectAlignToRect(&f1, Y, alignY, bounds);
    MKCGRectAlignToRect(&f1, X, alignX, bounds);
    line.layoutFrame = f1;
    
    CGRect f2 = CGRectZero;
    for(MKUILayoutConstraintItemAttribute *itemAttr in line.itemAttributs){
        f2 = itemAttr.layoutFrame;
        f2.origin.x += line.layoutFrame.origin.x;
        f2.origin.y += line.layoutFrame.origin.y;
        itemAttr.layoutFrame = f2;
        [itemAttr applyAttributeWithResizeItems:resizeItems];
    }
}
@end

MKDEF_EnumTypeCategories(MKUIEqualDivisionLayoutConstraintParam,
(@{
   @(MKUIEqualDivisionLayoutConstraintParam_H_C_C):@"H_C_C",
   @(MKUIEqualDivisionLayoutConstraintParam_H_C_L):@"H_C_L",
   @(MKUIEqualDivisionLayoutConstraintParam_H_C_R):@"H_C_R",
   @(MKUIEqualDivisionLayoutConstraintParam_H_T_C):@"H_T_C",
   @(MKUIEqualDivisionLayoutConstraintParam_H_T_L):@"H_T_L",
   @(MKUIEqualDivisionLayoutConstraintParam_H_T_R):@"H_T_R",
   @(MKUIEqualDivisionLayoutConstraintParam_H_B_L):@"H_B_L",
   @(MKUIEqualDivisionLayoutConstraintParam_H_B_C):@"H_B_C",
   @(MKUIEqualDivisionLayoutConstraintParam_H_B_R):@"H_B_R",
   @(MKUIEqualDivisionLayoutConstraintParam_V_C_C):@"V_C_C",
   @(MKUIEqualDivisionLayoutConstraintParam_V_C_L):@"V_C_L",
   @(MKUIEqualDivisionLayoutConstraintParam_V_C_R):@"V_C_R",
   @(MKUIEqualDivisionLayoutConstraintParam_V_T_C):@"V_T_C",
   @(MKUIEqualDivisionLayoutConstraintParam_V_T_L):@"V_T_L",
   @(MKUIEqualDivisionLayoutConstraintParam_V_T_R):@"V_T_R",
   @(MKUIEqualDivisionLayoutConstraintParam_V_B_C):@"V_B_C",
   @(MKUIEqualDivisionLayoutConstraintParam_V_B_L):@"V_B_L",
   @(MKUIEqualDivisionLayoutConstraintParam_V_B_R):@"V_B_R",
   }))
@implementation MKUIEqualDivisionLayoutConstraint(InitMethod)
//////////////////////////////////////////////////////////////////////////////
+ (NSDictionary<NSNumber *,NSArray<NSNumber *> *> *)ConstraintParamMap{
    static NSDictionary<NSNumber *,NSArray<NSNumber *> *> * __share__;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSMutableDictionary<NSNumber *,NSArray<NSNumber *> *> *map = [[NSMutableDictionary alloc] init];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_C_C)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_C_L)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_C_R)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_T_C)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_T_L)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_T_R)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_B_L)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_B_C)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_H_B_R)] = @[
          @(MKUILayoutConstraintDirectionHorizontal),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_C_C)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_C_L)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_C_R)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentCenter),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_T_C)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_T_L)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_T_R)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentTop),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_B_C)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentCenter),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_B_L)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentLeft),
          ];
        map[@(MKUIEqualDivisionLayoutConstraintParam_V_B_R)] = @[
          @(MKUILayoutConstraintDirectionVertical),
          @(MKUILayoutConstraintVerticalAlignmentBottom),
          @(MKUILayoutConstraintHorizontalAlignmentRight),
          ];
        __share__ = map;
    });
    return __share__;
}
+ (NSDictionary<NSArray<NSNumber *> *,NSNumber *> *)ConstraintParamRevertMap{
    static NSDictionary<NSArray<NSNumber *> *,NSNumber *> * __share__;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self ConstraintParamMap];
        NSMutableDictionary<NSArray<NSNumber *> *,NSNumber *> *map = [[NSMutableDictionary alloc] initWithCapacity:ConstraintParamMap.count];
        for (NSNumber *key in ConstraintParamMap) {
            map[ConstraintParamMap[key]] = key;
        }
        __share__ = map;
    });
    return __share__;
}
+ (void)parseConstraintParam:(MKUIEqualDivisionLayoutConstraintParam)param layoutDirection:(MKUILayoutConstraintDirection *)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment *)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment *)layoutHorizontalAlignment{
    NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self.class ConstraintParamMap];
    NSArray<NSNumber *> *enums = ConstraintParamMap[@(param)];
    *layoutDirection = [enums[0] integerValue];
    *layoutVerticalAlignment = [enums[1] integerValue];
    *layoutHorizontalAlignment = [enums[2] integerValue];
}
+ (MKUIEqualDivisionLayoutConstraintParam)constraintParamWithLayoutDirection:(MKUILayoutConstraintDirection)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment)layoutHorizontalAlignment{
    NSDictionary<NSArray<NSNumber *> *,NSNumber *> *ConstraintParamRevertMap = [self.class ConstraintParamRevertMap];
    MKUIEqualDivisionLayoutConstraintParam param = (MKUIEqualDivisionLayoutConstraintParam)[ConstraintParamRevertMap[@[@(layoutDirection),@(layoutVerticalAlignment),@(layoutHorizontalAlignment)]] integerValue];
    return param;
}
//////////////////////////////////////////////////////////////////////////////
- (id)initWithItems:(NSArray<id<MKUILayoutConstraintItemProtocol>> *)items constraintParam:(MKUIEqualDivisionLayoutConstraintParam)param contentInsets:(UIEdgeInsets)contentInsets interitemSpacing:(CGFloat)interitemSpacing{
    if(self=[self init]){
        self.items = items;
        self.contentInsets = contentInsets;
        self.interitemSpacing = interitemSpacing;
        [self configWithConstraintParam:param];
    }
    return self;
}
- (void)setConstraintParam:(MKUIEqualDivisionLayoutConstraintParam)constraintParam{
    [self configWithConstraintParam:constraintParam];
}
- (MKUIEqualDivisionLayoutConstraintParam)constraintParam{
    MKUIEqualDivisionLayoutConstraintParam param = [self.class constraintParamWithLayoutDirection:self.layoutDirection layoutVerticalAlignment:self.layoutVerticalAlignment layoutHorizontalAlignment:self.layoutHorizontalAlignment];
    return param;
}
- (void)configWithConstraintParam:(MKUIEqualDivisionLayoutConstraintParam)param{
    MKUILayoutConstraintDirection layoutDirection;
    MKUILayoutConstraintVerticalAlignment layoutVerticalAlignment;
    MKUILayoutConstraintHorizontalAlignment layoutHorizontalAlignment;
    [self.class parseConstraintParam:param layoutDirection:&layoutDirection layoutVerticalAlignment:&layoutVerticalAlignment layoutHorizontalAlignment:&layoutHorizontalAlignment];
    self.layoutDirection = layoutDirection;
    self.layoutVerticalAlignment = layoutVerticalAlignment;
    self.layoutHorizontalAlignment = layoutHorizontalAlignment;
}
@end
